package main

import (
	"context"
	"encoding/json"
	"fmt"
	"log"
	"medicine/internal/conf"
	"medicine/internal/data"
	"os"
	"time"

	"github.com/go-kratos/kratos/v2/config"
	filecfg "github.com/go-kratos/kratos/v2/config/file"
	"github.com/go-redis/redis/v8"
	"google.golang.org/protobuf/types/known/durationpb"
	"gopkg.in/yaml.v3"
)

// getConfigPath 智能获取配置文件路径
func getConfigPath() string {
	// 尝试多个可能的路径
	paths := []string{
		"configs/config.yaml",       // 从项目根目录运行
		"../configs/config.yaml",    // 从 cmd/rollback_consumer 运行
		"../../configs/config.yaml", // 从其他子目录运行
	}

	for _, path := range paths {
		if _, err := os.Stat(path); err == nil {
			return path
		}
	}

	// 如果都找不到，返回默认路径
	return "configs/config.yaml"
}

// 手动解析的配置结构
type ManualConfig struct {
	Data struct {
		Redis struct {
			Addr         string `yaml:"addr"`
			ReadTimeout  string `yaml:"read_timeout"`
			WriteTimeout string `yaml:"write_timeout"`
		} `yaml:"redis"`
		MQ struct {
			Addr string `yaml:"addr"`
		} `yaml:"mq"`
	} `yaml:"data"`
}

func main() {
	configPath := getConfigPath()
	fmt.Printf("使用配置文件路径: %s\n", configPath)

	// 先尝试直接读取 YAML 文件
	yamlData, err := os.ReadFile(configPath)
	if err != nil {
		log.Fatalf("读取配置文件失败: %v", err)
	}

	var rawConfig map[string]interface{}
	if err := yaml.Unmarshal(yamlData, &rawConfig); err != nil {
		log.Fatalf("解析 YAML 失败: %v", err)
	}

	fmt.Printf("原始配置: %+v\n", rawConfig)

	// 尝试用 Kratos 解析
	var bc conf.Bootstrap
	if err := config.New(config.WithSource(filecfg.NewSource(configPath))).Scan(&bc); err != nil {
		log.Printf("Kratos 配置解析失败: %v，尝试手动解析", err)
		bc = conf.Bootstrap{}
	}

	// 如果 Kratos 解析失败，手动解析
	if bc.Data == nil || bc.Data.Mq == nil {
		fmt.Println("使用手动解析配置...")
		var manualConfig ManualConfig
		if err := yaml.Unmarshal(yamlData, &manualConfig); err != nil {
			log.Fatalf("手动解析配置失败: %v", err)
		}

		// 手动创建配置结构
		bc.Data = &conf.Data{
			Redis: &conf.Data_Redis{
				Addr: manualConfig.Data.Redis.Addr,
			},
			Mq: &conf.Data_MQ{
				Addr: manualConfig.Data.MQ.Addr,
			},
		}

		// 解析超时时间
		if readTimeout, err := time.ParseDuration(manualConfig.Data.Redis.ReadTimeout); err == nil {
			bc.Data.Redis.ReadTimeout = &durationpb.Duration{
				Seconds: int64(readTimeout.Seconds()),
				Nanos:   int32(readTimeout.Nanoseconds() % 1e9),
			}
		}
		if writeTimeout, err := time.ParseDuration(manualConfig.Data.Redis.WriteTimeout); err == nil {
			bc.Data.Redis.WriteTimeout = &durationpb.Duration{
				Seconds: int64(writeTimeout.Seconds()),
				Nanos:   int32(writeTimeout.Nanoseconds() % 1e9),
			}
		}
	}

	fmt.Printf("配置加载成功，Data: %+v\n", bc.Data)
	if bc.Data != nil {
		fmt.Printf("Data.Mq: %+v\n", bc.Data.Mq)
	}

	if bc.Data == nil || bc.Data.Mq == nil {
		panic("配置文件 data.mq 缺失或格式错误，请检查 config.yaml")
	}
	mqAddr := bc.Data.Mq.Addr

	// 连接Redis
	redisConf := bc.Data.Redis
	rdb := redis.NewClient(&redis.Options{
		Addr:         redisConf.Addr,
		ReadTimeout:  redisConf.ReadTimeout.AsDuration(),
		WriteTimeout: redisConf.WriteTimeout.AsDuration(),
	})
	ctx := context.Background()

	// 连接RabbitMQ
	mq, err := data.NewMQClient(mqAddr)
	if err != nil {
		log.Fatalf("MQ连接失败: %v", err)
	}
	defer mq.Close()

	// 声明队列
	_, err = mq.Channel.QueueDeclare("seckill_rollback", true, false, false, false, nil)
	if err != nil {
		log.Fatalf("声明队列失败: %v", err)
	}

	msgs, err := mq.Channel.Consume("seckill_rollback", "", true, false, false, false, nil)
	if err != nil {
		log.Fatalf("消费队列失败: %v", err)
	}

	log.Println("回滚库存消费者启动...")
	for d := range msgs {
		var msg data.StockRollbackMsg
		if err := json.Unmarshal(d.Body, &msg); err != nil {
			log.Printf("消息解析失败: %v", err)
			continue
		}
		stockKey := fmt.Sprintf("seckill:stock:%d", msg.SeckillProductID)
		if err := rdb.IncrBy(ctx, stockKey, int64(msg.Quantity)).Err(); err != nil {
			log.Printf("回滚库存失败: %v", err)
		} else {
			log.Printf("回滚库存成功: 商品ID=%d, 数量=%d", msg.SeckillProductID, msg.Quantity)
		}
		time.Sleep(10 * time.Millisecond) // 防止刷屏
	}
}
